package com.meisen.springboot.controller;

import com.alibaba.druid.support.json.JSONUtils;
import com.meisen.springboot.entity.SysRole;
import com.meisen.springboot.entity.User;
import com.meisen.springboot.request.UserRequest;
import com.meisen.springboot.response.ResultEntity;
import com.meisen.springboot.exception.ServerException;
import com.meisen.springboot.response.UserResponse;
import com.meisen.springboot.service.UserService;
import com.meisen.springboot.util.Encrypt;
import com.meisen.springboot.util.Result;
import org.apache.logging.log4j.util.Strings;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 用户controller
 * 包含功能：
 * 1. 注册 id为UUID, 密码通过MD5加密
 * 2. 登录 通过用户名登录
 * 3. 查找 通过id查找用户
 * @author meisen
 * 2018-04-17
 */
@RestController
@RequestMapping("/api/user")
public class UserController {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);

    private static final String PRODUCE_JSON = "application/json; charset=UTF-8";
    private static final String USER_ID = "userId";

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    /**
     * 登录
     * @return 登录结果
     */
    @RequestMapping(path = "/login", method = RequestMethod.POST, produces = PRODUCE_JSON)
    public ResultEntity login(@RequestBody UserRequest userRequest) {
        validateUserRequest(userRequest, "登录错误, 参数校验失败.");
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userRequest.getUsername(), userRequest.getPassword());
        UserResponse userResponse = new UserResponse();
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            userResponse.setId(subject.getSession().getId());
            userResponse.setUsername(userRequest.getUsername());
            userResponse.setStatus("ok");
            if (null != user.getRoleList()) {
                List<String> roles = user.getRoleList().stream().map(SysRole::getRole).collect(Collectors.toList());
                userResponse.setRole(roles);
            }
            userResponse.setCurrentAuthority("admin");
        } catch (IncorrectCredentialsException e) {
            return Result.error(1, "密码错误");
        } catch (LockedAccountException e) {
            return Result.error(2, "账户被锁定，无法登录");
        } catch (UnknownAccountException e) {
            return Result.error(3, "用户不存在");
        } catch (Exception e) {
            LOGGER.error("登录失败" + e.getMessage());
            return Result.error(4, "登录失败，未知错误");
        }
        return Result.success(userResponse, "登录成功");
    }

    @RequestMapping(path = "/logout", produces = PRODUCE_JSON)
    public ResultEntity logout() {
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.logout();
        } catch (Exception e) {
            return Result.error(1, "登出失败" + e.getMessage());
        }
        return Result.success(0, "登出成功");
    }

    /**
     * 注册用户
     * @param userRequest 用户请求
     * @return 结果Result： 正常: 0
     */
    @RequestMapping(path = "/register", method = RequestMethod.POST, produces = PRODUCE_JSON)
    public ResultEntity register(@RequestBody UserRequest userRequest) {
        validateUserRequest(userRequest, "注册错误，用户名或密码未输入.");
        String username = userRequest.getUsername();
        if (!User.NO_SUCH_USER.equals(userService.findUserByUsername(username).getUsername())) {
            LOGGER.error("注册错误，用户{}已存在，请使用其他用户名.", username);
            return Result.error(1, "注册错误，用户已存在，请使用其他用户名.");
        }
        String password = new SimpleHash("MD5", userRequest.getPassword(), username + Encrypt.SALT, 2).toHex();
        User registerUser = new User();
        registerUser.setUsername(username);
        registerUser.setPassword(password);
        registerUser.setState(Byte.valueOf("0"));
        registerUser.setSalt(Encrypt.SALT);
        User user = userService.registerUser(registerUser);
        UserResponse response = new UserResponse();
        response.setId(user.getUid());
        response.setUsername(user.getUsername());
        return Result.success(response, "注册成功");
    }

    /**
     * 删除制定用户
     * @param id 用户id
     * @return 结果Result
     */
    @GetMapping(path = "/remove", produces = PRODUCE_JSON)
    public ResultEntity remove(@RequestParam String id) {
        if (Strings.isBlank(id)) {
            LOGGER.error("删除用户出错， 请输入用户id");
            return Result.error(1, "删除用户出错， 请输入用户id");
        }
        userService.removeUser(id);
        return Result.success(null, "删除成功");
    }

    @GetMapping(path = "/currentUser", produces = PRODUCE_JSON)
    public ResultEntity info() {
        Subject subject = SecurityUtils.getSubject();
        User user = (User) subject.getPrincipal();
        UserResponse response = new UserResponse();
        response.setId(user.getUid());
        response.setUsername(user.getUsername());
        return Result.success(response, null);
    }

    /**
     * 修改用户
     * @param userRequest 用户输入
     * @return result
     */
    @RequestMapping(path = "/modify", method = RequestMethod.POST)
    public ResultEntity update(@RequestBody UserRequest userRequest) {
        validateUserRequest(userRequest, "修改用户错误, 用户名或密码未输入!");
        String username = userRequest.getUsername();
        String password = userRequest.getPassword();
        User user = userService.saveOrUpdateUser(new User(username, Encrypt.encrypt(password)));
        LOGGER.info("更新用户成功");
        return Result.success(user, "更新用户成功");
    }

    @RequestMapping(path = "/unauth")
    public ResultEntity unauth() {
        return Result.error(101, "用户未登录");
    }

    /**
     * 检查入参
     * @param userRequest 用户输入
     * @param errorMsg 错误信息
     */
    private void validateUserRequest(UserRequest userRequest, String errorMsg) {
        if (userRequest == null || !Strings.isNotEmpty(userRequest.getUsername()) || !Strings.isNotEmpty(userRequest.getPassword())) {
            LOGGER.error(errorMsg + "{}", JSONUtils.toJSONString(userRequest));
            throw new ServerException(1, errorMsg);
        }
    }
}
